// // Copyright (c) 2014-present, b3log.org
// //
// // Licensed under the Apache License, Version 2.0 (the "License");
// // you may not use this file except in compliance with the License.
// // You may obtain a copy of the License at
// //
// //     https://www.apache.org/licenses/LICENSE-2.0
// //
// // Unless required by applicable law or agreed to in writing, software
// // distributed under the License is distributed on an "AS IS" BASIS,
// // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// // See the License for the specific language governing permissions and
// // limitations under the License.

package output

// import (
// 	"bufio"
// 	"encoding/hex"
// 	"encoding/json"
// 	"errors"
// 	"io"
// 	"io/ioutil"
// 	"math/rand"
// 	"net/http"
// 	"os"
// 	"os/exec"
// 	"path/filepath"
// 	"runtime"
// 	"strconv"
// 	"strings"
// 	"time"

// 	"chainmaker.org/chainmaker/smarteditor/common"
// 	"chainmaker.org/chainmaker/smarteditor/conf"
// 	"chainmaker.org/chainmaker/smarteditor/file"
// 	"chainmaker.org/chainmaker/smarteditor/global"
// 	"chainmaker.org/chainmaker/smarteditor/i18n"
// 	"chainmaker.org/chainmaker/smarteditor/session"
// 	"chainmaker.org/chainmaker/smarteditor/util"
// 	"github.com/88250/gulu"
// 	"github.com/tjfoc/gmsm/sm3"
// )

// const WindowsSuffix = ".exe"

// type buildInfo struct {
// 	ContractName   string   `json:"contract_name,omitempty"`
// 	Date           string   `json:"date,omitempty"`
// 	Hash           string   `json:"hash,omitempty"`
// 	Methods        []string `json:"methods,omitempty"`
// 	SourceCodeHash string   `json:"source_code_hash"`
// }

// type buildResponse struct {
// 	File string `json:"file"`
// }

// // CrossCompilationHandler handles request of cross compilation.
// func CrossCompilationHandler(w http.ResponseWriter, r *http.Request) {
// 	uid, err := session.GetUidFromSession(r)
// 	if err != nil {
// 		log.Errorf("CrossCompilationHandler Forbidden. url:%s,uid:%s, err:%v", r.URL, uid, err)
// 		http.Error(w, "Forbidden", http.StatusForbidden)
// 		return
// 	}

// 	result := gulu.Ret.NewResult()
// 	defer gulu.Ret.RetResult(w, r, result)

// 	var args map[string]interface{}
// 	if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
// 		log.Errorf("CrossCompilationHandler decode parameter failed. url:%s, err:%v", r.URL, err)
// 		result.Code = -1
// 		return
// 	}
// 	sid := args["sid"].(string)
// 	path := args["path"].(string)
// 	platform := args["platform"].(string)

// 	if sid == "" || path == "" || platform == "" {
// 		http.Error(w, "parameter error", http.StatusBadRequest)
// 		return
// 	}
// 	if !file.HasAccessPermission(uid, path) {
// 		http.Error(w, "not permission", http.StatusUnauthorized)
// 		return
// 	}

// 	workspace := conf.GetUserWorkspace(uid)

// 	if !util.IsContractRootDirectory(workspace, filepath.Dir(path)) {
// 		log.Errorf("cross compile handler, file path is not contract root path, don't need build. uid:%s, workspace:%s, file path:%s", uid, sid, path)
// 		result.Code = -1
// 		return
// 	}

// 	curDirectory := filepath.Dir(path)
// 	if !gulu.File.IsExist(filepath.Join(curDirectory, "go.mod")) {
// 		output, err := util.RunGoModInit(uid, curDirectory, workspace, conf.Docker)
// 		if err != nil {
// 			sendBuildErrorMessageToWs(uid, sid, output)
// 			log.Errorf("CrossCompilationHandler init go mod fail. output:%s, err:%v", output, err)
// 			result.Code = -1
// 			return
// 		}
// 		//执行go get获取指定依赖
// 		//output, err = util.RunGoGet(uid, curDirectory, workspace, conf.Docker)
// 		//if err != nil {
// 		//	sendBuildErrorMessageToWs(uid, sid, output)
// 		//	log.Errorf("build handler go get fail. output:%s, err:%v", output, err)
// 		//	result.Code = -1
// 		//	return
// 		//}
// 	}
// 	output, err := util.RunGoModTidy(uid, curDirectory, workspace, conf.Docker)
// 	if err != nil {
// 		sendBuildErrorMessageToWs(uid, sid, output)
// 		log.Errorf("CrossCompilationHandler init go tidy fail. output:%s, err:%v", output, err)
// 		result.Code = -1
// 		return
// 	}
// 	session.SendUpdateFileEvent(sid, filepath.Join(curDirectory, util.GoModFile))
// 	session.SendUpdateFileEvent(sid, filepath.Join(curDirectory, util.GoSumFile))

// 	goos := strings.Split(platform, "_")[0]
// 	goarch := strings.Split(platform, "_")[1]
// 	suffix := ""
// 	if "windows" == goos {
// 		suffix = WindowsSuffix
// 	}
// 	executableFileName := filepath.Join(curDirectory, filepath.Base(curDirectory)+suffix)
// 	name := filepath.Base(curDirectory) + "-" + goos + "-" + goarch

// 	user := conf.GetUser(uid)
// 	var goBuildArgs []string
// 	goBuildArgs = append(goBuildArgs, "build", "-o", executableFileName)
// 	log.Errorf("go build 230执行参数为:%s curDirectory:%s", goBuildArgs, curDirectory)
// 	cmd := exec.Command("go", goBuildArgs...)
// 	cmd.Dir = curDirectory
// 	//非测试环境执行环境变量设置
// 	if global.TestnetEnv != true {
// 		setCmdEnvWithOsAndArchAndGoRoot(cmd, uid, goos, goarch, runtime.GOROOT()+RealSdkGoRootSuffix)
// 	}

// 	stdout, stderr, err := util.OpenStdOutAndStdErr(cmd)
// 	if err != nil {
// 		log.Errorf("CrossCompilationHandler open stdout and stderr failed. err:%s", err)
// 		result.Code = -1
// 		result.Msg = err.Error()
// 		return
// 	}

// 	err = writeStartBuildMessageToWebSocket(sid, uid, user.Locale)
// 	if err != nil {
// 		log.Errorf("CrossCompilationHandler write start build message to websocket failed.uid:%s, err :%s", uid, err)
// 		result.Code = -1
// 		result.Msg = err.Error()
// 		return
// 	}

// 	if err := cmd.Start(); nil != err {
// 		log.Errorf("CrossCompilationHandler start cmd faild. err:%s", err)
// 		result.Code = -1
// 		result.Msg = err.Error()
// 		return
// 	}

// 	WaitCmdRunSuccess(rand.Int(), cmd, stdout, stderr, user.Locale, executableFileName, name, curDirectory, sid)

// 	file7z, err := generateBuildAndDeployFile(curDirectory, workspace, executableFileName, uid)
// 	if err != nil {
// 		log.Errorf("CrossCompilationHandler generate build file fail. err:%s", err)
// 		result.Code = -1
// 		result.Msg = err.Error()
// 		return
// 	}

// 	result.Data = buildResponse{File: file7z}
// }

// func writeStartBuildMessageToWebSocket(sid, uid, locale string) error {
// 	channelRet := map[string]interface{}{}
// 	if wsChannel, err := session.GetOutputWS(sid); err == nil {
// 		channelRet["output"] = "<span class='start-build'>" + i18n.Get(locale, "start-build").(string) + "</span>\n"
// 		channelRet["cmd"] = "start-build"
// 		err := wsChannel.WriteJSON(&channelRet)
// 		if nil != err {
// 			return errors.New("write message to socket failed")
// 		}
// 		wsChannel.Refresh()
// 	} else {
// 		log.Errorf("CrossCompilationHandler websocket not found. uid:%s, msg:%v", uid, channelRet)
// 		return errors.New("web socket not found")
// 	}
// 	return nil
// }

// func WaitCmdRunSuccess(runningID int, cmd *exec.Cmd, stdout io.ReadCloser, stderr io.ReadCloser,
// 	locale, executable, name, curDirectory, sid string) {
// 	log.Debugf("WaitCmdRunSuccess start. directory%s, sid:%s, runing id:%d", curDirectory, sid, runningID)
// 	defer util.PanicLog()
// 	bytes, err := ioutil.ReadAll(bufio.NewReader(io.MultiReader(stdout, stderr)))
// 	if err != nil {
// 		log.Infof("WaitCmdRunSuccess read stdout std err failed. err:%s", err)
// 		return
// 	}
// 	stdOutput := string(bytes)
// 	channelRet := map[string]interface{}{}
// 	channelRet["cmd"] = "cross-build"
// 	channelRet["executable"] = executable
// 	channelRet["name"] = name

// 	if 0 == len(stdOutput) { // build success
// 		log.Warnf("WaitCmdRunSuccess std output: %s", stdOutput)
// 		channelRet["output"] = "<span class='build-succ'>" + i18n.Get(locale, "build-succ").(string) + "</span>\n"
// 	} else {
// 		lines := strings.Split(stdOutput, "\n")
// 		var stdOutWithPath string
// 		for _, line := range lines {
// 			stdOutWithPath += parsePath(curDirectory, line) + "\n"
// 		}

// 		channelRet["output"] = "<span class='build-error'>" + i18n.Get(locale, "build-error").(string) + "</span>\n" +
// 			"<span class='stderr'>" + stdOutWithPath + "</span>"

// 		channelRet["lints"] = parseLints(lines, curDirectory)
// 	}

// 	if wsChannel, err := session.GetOutputWS(sid); err == nil {
// 		err := wsChannel.WriteJSON(&channelRet)
// 		if nil != err {
// 			log.Errorf("WaitCmdRunSuccess write message to websocket error. err:%s", err)
// 		}
// 		wsChannel.Refresh()
// 	}

// 	err = cmd.Wait()
// 	if err != nil {
// 		log.Errorf("WaitCmdRunSuccess cmd wait error. err:%s", err)
// 	}
// }

// func parseLints(lines []string, curDirectory string) []*Lint {
// 	lints := make([]*Lint, 0)

// 	if lines[0][0] == '#' {
// 		lines = lines[1:] // skip the first line
// 	}

// 	for _, line := range lines {
// 		if len(line) < 1 {
// 			continue
// 		}

// 		if line[0] == '\t' {
// 			last := len(lints)
// 			msg := lints[last-1].Msg
// 			msg += line
// 			lints[last-1].Msg = msg
// 			continue
// 		}

// 		fileName := line[:strings.Index(line, ":")]
// 		left := line[strings.Index(line, ":")+1:]
// 		index := strings.Index(left, ":")
// 		lineNo := 0
// 		var err error
// 		msg := left
// 		if index >= 0 {
// 			lineNo, err = strconv.Atoi(left[:index])
// 			if nil != err {
// 				continue
// 			}
// 			msg = left[index+2:]
// 		}

// 		lint := &Lint{
// 			File:     filepath.Join(curDirectory, fileName),
// 			LineNo:   lineNo - 1,
// 			Severity: lintSeverityError,
// 			Msg:      msg,
// 		}

// 		lints = append(lints, lint)
// 	}
// 	return lints
// }

// // generateBuildFile generate build file after build
// func generateBuildAndDeployFile(curDirectory, workspace, executableFile, uid string) (string, error) {
// 	//create build directory
// 	contractDirectoryName := filepath.Base(curDirectory)

// 	buildDirectory, err := conf.CreateBuildContractDir(workspace, contractDirectoryName)
// 	if err != nil {
// 		log.Errorf("generateBuildFile create build directory fail.uid:%s, err :%s", uid, err)
// 		return "", err
// 	}

// 	//copy executable file to build directory
// 	deployExecutableFile := filepath.Join(buildDirectory, filepath.Base(executableFile))
// 	err = util.CopyFile(executableFile, deployExecutableFile)
// 	if err != nil {
// 		log.Errorf("generateBuildFile copy file fail.uid:%s, err :%s", uid, err)
// 		return "", err
// 	}
// 	//compress executable file to build directory
// 	fileName7z, err := util.Compress7z(buildDirectory, filepath.Base(executableFile))
// 	if err != nil {
// 		log.Errorf("generateBuildFile compress file fail. uid:%s, build dir:%s, execute file:%s,  err :%s",
// 			uid, buildDirectory, executableFile, err)
// 		return "", err
// 	}
// 	//remove executable file
// 	err = os.Remove(executableFile)
// 	if err != nil {
// 		log.Errorf("generateBuildFile remove executable file fail. uid:%s, executable file:%s, err :%s",
// 			uid, executableFile, err)
// 		return "", err
// 	}

// 	//create deploy directory
// 	deployDirectory, err := conf.CreateDeployContractDir(workspace, contractDirectoryName)
// 	if err != nil {
// 		log.Errorf("generateBuildFile create deploy directory fail. "+
// 			"uid:%s, workspace:%s, contract dir name:%s, err :%s", uid, workspace, contractDirectoryName, err)
// 		return "", err
// 	}

// 	file7z := filepath.Join(buildDirectory, fileName7z)
// 	fileData, err := ioutil.ReadFile(file7z)
// 	sm3Sum := sm3.Sm3Sum(fileData)
// 	md5SumHex := hex.EncodeToString(sm3Sum[:])

// 	hashDir, err := conf.CreateDeployHashDir(deployDirectory, md5SumHex)
// 	if err != nil {
// 		log.Errorf("generateBuildFile create has directory fail. "+
// 			"uid:%s, deploy dir:%s, md5:%s, hash dir:%s, err :%s",
// 			uid, deployDirectory, md5SumHex, hashDir, err)
// 		return "", err
// 	}

// 	source7zName := conf.GetSource7zName()
// 	compressSource := curDirectory
// 	compressTarget := filepath.Join(hashDir, source7zName)
// 	//compress source code to 7z
// 	err = util.Compress7zSourceToTarget(compressSource, compressTarget)
// 	if err != nil {
// 		log.Errorf("generateBuildFile compress source code fial. "+
// 			"uid:%s,compress source:%s,compress target:%s, err :%s", uid, compressSource, compressTarget, err)
// 		return "", err
// 	}

// 	//source code hash
// 	sourceCodeData, err := ioutil.ReadFile(compressTarget)
// 	sourceCodeSm3Sum := sm3.Sm3Sum(sourceCodeData)
// 	sourceCodeMd5SumHex := hex.EncodeToString(sourceCodeSm3Sum[:])

// 	//append hash to hash file
// 	hashFile, err := conf.AppendDataToDeployHashFile(deployDirectory, sourceCodeMd5SumHex+":"+md5SumHex)
// 	if err != nil {
// 		log.Errorf("generateBuildFile append hash to hash file fail. "+
// 			"uid:%s, deploy dir:%s, md5:%s, hash file:%s, err :%s",
// 			uid, deployDirectory, md5SumHex, hashFile, err)
// 		return "", err
// 	}

// 	//copy binary file
// 	hashExecutableFile := filepath.Join(hashDir, filepath.Base(executableFile))
// 	err = util.CopyFile(deployExecutableFile, hashExecutableFile)
// 	if err != nil {
// 		log.Errorf("generateBuildFile copy binary file fial. "+
// 			"uid:%s, source:%s, target:%s, err :%s", uid, deployExecutableFile, hashExecutableFile, err)
// 		return "", err
// 	}
// 	//copy compress file
// 	source7z := filepath.Join(buildDirectory, fileName7z)
// 	target7z := filepath.Join(hashDir, fileName7z)
// 	err = util.CopyFile(source7z, target7z)
// 	if err != nil {
// 		log.Errorf("generateBuildFile copy compress file fial. "+
// 			"uid:%s, source:%s, target:%s, err :%s", uid, source7z, target7z, err)
// 		return "", err
// 	}
// 	//persistence build info
// 	contractBuildInfo := generateBuildInfo(curDirectory, contractDirectoryName, md5SumHex, sourceCodeMd5SumHex)
// 	marshalBuildInfo, err := json.Marshal(contractBuildInfo)
// 	if err != nil {
// 		log.Errorf("generateBuildFile marshal build info fial. "+
// 			"uid:%s, path:%s, contarct name:%s, md5sum:%s, err :%s",
// 			uid, curDirectory, contractDirectoryName, md5SumHex, err)
// 		return "", err
// 	}
// 	buildInfoFile := filepath.Join(buildDirectory, conf.GetBuildInfoName())
// 	err = ioutil.WriteFile(buildInfoFile, marshalBuildInfo, 0644)
// 	if err != nil {
// 		log.Errorf("generateBuildFile write build info to file fail. "+
// 			"uid:%s, file:%s, build info:%s, err :%s", uid, buildInfoFile, string(marshalBuildInfo), err)
// 		return "", err
// 	}
// 	err = ioutil.WriteFile(filepath.Join(hashDir, conf.GetBuildInfoName()), marshalBuildInfo, 0644)
// 	if err != nil {
// 		log.Errorf("generateBuildFile write build info to file fail. "+
// 			"uid:%s, file:%s, build info:%s, err :%s", uid, buildInfoFile, string(marshalBuildInfo), err)
// 	}
// 	return file7z, nil
// }

// func generateBuildInfo(path, contractName, md5sum, SourceCodeHash string) *buildInfo {
// 	result := buildInfo{
// 		ContractName:   contractName,
// 		Date:           time.Now().Format(common.TimeLayout),
// 		Hash:           md5sum,
// 		Methods:        getMethodFromPath(path),
// 		SourceCodeHash: SourceCodeHash,
// 	}
// 	return &result
// }

// func getMethodFromPath(path string) []string {
// 	methods, err := session.GetMethodsFormPath(path)
// 	if err != nil {
// 		log.Warnf("get method fail. path:%s", path)
// 		return make([]string, 0)
// 	}
// 	return methods
// }
